﻿using System;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;


#region assembly resources

[assembly: System.Web.UI.WebResource("TrainingsApp.Controls.TextControlExt.Resource.JScript.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("TrainingsApp.Controls.TextControlExt.Resource.Calendar.js", "text/javascript")]
[assembly: System.Web.UI.WebResource("TrainingsApp.Controls.TextControlExt.Resource.exclamation.gif", "image/gif")]
[assembly: System.Web.UI.WebResource("TrainingsApp.Controls.TextControlExt.Resource.invalid_line.gif", "image/gif")]
#endregion

namespace TrainingsApp.Controls.TextControlExt
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:TextControlExt runat=server></{0}:TextControlExt>")]
    public class TextControlExt : TextBox
    {

        #region 控件属性
        /// <summary>
        /// 文本模式
        /// </summary>
        [Description(@"文本框输入的类型：
                        String------任意文本,
                        Upper---------大写,
                        Lower---------小写,
                        Number--------任意数字,
                        Float--格式化指定的小数,
                        Date----------日期,
                        Chinese-中文,
                        Email---------邮箱,
                        Phone---------固定电话
        ")]
        public ValidMode ValidMode
        {
            get
            {
                return ViewState["ValidMode"] == null ? ValidMode.Never : (ValidMode)ViewState["ValidMode"];
            }
            set
            {
                if ((value < ValidMode.Never) || (value > ValidMode.Custom))
                {
                    throw new ArgumentOutOfRangeException("属性值无效");
                }

                ViewState["ValidMode"] = value;
            }
        }


        [Description("控件获得焦点的样式名称")]
        public string OnfocusCssName
        {
            get
            {
                return ViewState["OnfocusCssName"] == null ? string.Empty : (string)ViewState["OnfocusCssName"];
            }
            set
            {
                ViewState["OnfocusCssName"] = value;
            }
        }

        /// <summary>
        /// 控件失去焦点的样式
        /// </summary>
        [Description("控件失去焦点的样式名称")]
        public string OnblurCssName
        {
            get
            {
                return ViewState["OnblurCssName"] == null ? string.Empty : (string)ViewState["OnblurCssName"];
            }
            set
            {
                ViewState["OnblurCssName"] = value;
            }
        }


        [Description("当是浮点数时,指定保留的小数位数")]
        [DefaultValue("2")]
        public string FloatLength
        {
            get
            {
                return ViewState["FloatLength"] == null ? "2" : (string)ViewState["FloatLength"];
            }
            set
            {
                if (Int64.Parse(value) < 0)
                    throw new ArgumentOutOfRangeException("小数位数至少保留一位小数,如无需保留请选择整形");

                ViewState["FloatLength"] = value;
            }
        }


        [Bindable(true)]
        [Browsable(true)]
        [Category("自定义信息区")]
        [Description("自定义用于验证的正则表达式，ValidMode 为 Custom 时有效")]
        [DefaultValue("")]
        public string CustomRegexExpression
        {
            get
            {
                return ViewState["CustomRegexExpression"] == null ? "" : (string)ViewState["CustomRegexExpression"];
            }
            set
            {
                ViewState["CustomRegexExpression"] = value;
            }
        }


        /// <summary>
        /// 验证控件文本是否必须
        /// </summary>
        [Description("验证控件文本是否必须")]
        public bool ValidateRequired
        {
            get
            {
                return ViewState["ValidateRequired"] == null ? false : (bool)ViewState["ValidateRequired"];
            }
            set
            {
                ViewState["ValidateRequired"] = value;
            }
        }

        /// <summary>
        /// 回车是否跳格
        /// </summary>
        [DefaultValue(true), Description("回车是否跳格")]
        public bool EnterToTab
        {
            get
            {
                return ViewState["EnterToTab"] == null ? true : (bool)ViewState["EnterToTab"];
            }
            set
            {
                ViewState["EnterToTab"] = value;
            }
        }


        [Browsable(true), Category("自定义信息区"), Description("显示验证错误信息样式"), DefaultValue("")]
        public string DisplayErrorCss
        {
            get
            {
                return ViewState["DisplayErrorCss"] == null ? "" : (string)ViewState["DisplayErrorCss"];
            }
            set
            {
                ViewState["DisplayErrorCss"] = value;
            }
        }

        [Browsable(true), Category("自定义信息区"), Description("隐藏验证错误信息样式"), DefaultValue("")]
        public string HideErrorCss
        {
            get
            {
                return ViewState["HideErrorCss"] == null ? "" : (string)ViewState["HideErrorCss"];
            }
            set
            {
                ViewState["HideErrorCss"] = value;
            }
        }

        [Browsable(true), Category("自定义信息区"), Description("自定义验证错误信息")]
        public string DisplayError
        {
            get
            {
                return ViewState["DisplayError"] == null ? "此项不能为空或格式不正确" : (string)ViewState["DisplayError"];
            }
            set
            {
                ViewState["DisplayError"] = value;
            }
        }

        [Browsable(false), Category("自定义信息区"), Description("查询字符串值")]
        public string ParameterValue
        {
            get
            {
                return string.IsNullOrEmpty(Text) ? "%" : Text;
            }
        }
        ///// <summary>
        ///// 失去焦点时触发客户端事件
        ///// </summary>
        //[Browsable(true), Category("自定义信息区"), Description("失去焦点时触发客户端事件")]
        //public string OnblurEvent
        //{
        //    get
        //    {
        //        return ViewState["OnblurEvent"] == null ? "" : (string)ViewState["OnblurEvent"];
        //    }
        //    set
        //    {
        //        ViewState["OnblurEvent"] = value;
        //    }
        //}


        [Bindable(true)]
        [Category("Appearance")]
        [Localizable(true)]
        public override string Text
        {
            get
            {
                String s = (String)ViewState["Text"];

                return (s == null) ? string.Empty : s;
            }

            set
            {
                ViewState["Text"] = value;
            }
        }

        #endregion

        #region 重写基类方法

        protected override void OnPreRender(EventArgs e)
        {

            if (this.Page != null)
            {
                if (ValidMode == ValidMode.Date)
                {
                    if (!this.Page.ClientScript.IsClientScriptIncludeRegistered(this.GetType(), "Calendar"))
                    {
                        this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "Calendar", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "TrainingsApp.Controls.TextControlExt.Resource.Calendar.js"));
                    }
                }
                else
                {
                    if (!this.Page.ClientScript.IsClientScriptIncludeRegistered(this.GetType(), "Custom"))
                    {
                        this.Page.ClientScript.RegisterClientScriptInclude(typeof(TreeView), "Custom", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "TrainingsApp.Controls.TextControlExt.Resource.JScript.js"));
                    }
                }
            }

            base.OnPreRender(e);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);

            if (ValidateRequired || ValidMode != ValidMode.Never)
            {
                string imgUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "TrainingsApp.Controls.TextControlExt.Resource.exclamation.gif");

                writer.WriteBeginTag(string.Format("img id='rfv{0}' src='{1}' title='{2}' style='{3}'>", this.UniqueID, imgUrl, DisplayError, "display:none;vertical-align:middle"));
                writer.WriteEndTag("img");
            }


        }

        /// <summary>
        /// 重写属性输出函数
        /// </summary>
        /// <param name="writer">要写出到的 HTML 编写器</param>
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            try
            {
                bool imeMode = false;

                switch (ValidMode)
                {
                    case ValidMode.Date:
                        this.Attributes.Add("onfocus", "calendar(EventUtil.getEvent().target)");
                        imeMode = true;
                        break;
                    case ValidMode.Float:
                        //小数
                        this.Attributes.Add("onkeypress", string.Format(Regular.Onkeypress, @"/^\d*\.?\d{0," + this.FloatLength + "}$/"));
                        this.Attributes.Add("onpaste", string.Format(Regular.Onpaste, @"/^\d*\.?\d{0," + this.FloatLength + "}$/"));
                        this.Attributes.Add("ondrop", string.Format(Regular.Ondrop, @"/^\d*\.?\d{0," + this.FloatLength + "}$/"));
                        writer.AddAttribute("ValidateMode", "Float");
                        imeMode = true;
                        break;
                    case ValidMode.Lower:
                        //小写
                        this.Attributes.Add("onkeypress", string.Format(Regular.Onkeypress, Regular.Lower));
                        this.Attributes.Add("onpaste", string.Format(Regular.Onpaste, Regular.Lower));
                        this.Attributes.Add("ondrop", string.Format(Regular.Ondrop, Regular.Lower));
                        writer.AddStyleAttribute("text-transform", "lowercase");
                        imeMode = true;

                        break;
                    case ValidMode.Upper:
                        //大写
                        this.Attributes.Add("onkeypress", string.Format(Regular.Onkeypress, Regular.Upper));
                        this.Attributes.Add("onpaste", string.Format(Regular.Onpaste, Regular.Upper));
                        this.Attributes.Add("ondrop", string.Format(Regular.Ondrop, Regular.Upper));
                        writer.AddStyleAttribute("text-transform", "uppercase");
                        imeMode = true;
                        break;
                    case ValidMode.Number:
                        //数字
                        this.Attributes.Add("onkeypress", string.Format(Regular.Onkeypress, Regular.Number));
                        this.Attributes.Add("onpaste", string.Format(Regular.Onpaste, Regular.Number));
                        this.Attributes.Add("ondrop", string.Format(Regular.Ondrop, Regular.Number));
                        writer.AddAttribute("ValidateMode", "Int");
                        imeMode = true;
                        break;
                    case ValidMode.Mail:
                        writer.AddAttribute("ValidateMode", "Email");
                        imeMode = true;
                        break;
                    case ValidMode.Url:
                        writer.AddAttribute("ValidateMode", "Url");
                        imeMode = true;
                        break;
                    case ValidMode.PostalCode:
                        writer.AddAttribute("ValidateMode", "PostalCode");
                        imeMode = true;
                        break;
                    case ValidMode.Mobile:
                        writer.AddAttribute("ValidateMode", "MobilePhone");
                        imeMode = true;
                        break;

                    case ValidMode.Phone:
                        //固话
                        this.Attributes.Add("onkeypress", string.Format(Regular.Onkeypress, Regular.Phone));
                        this.Attributes.Add("onpaste", string.Format(Regular.Onpaste, Regular.Phone));
                        this.Attributes.Add("ondrop", string.Format(Regular.Ondrop, Regular.Phone));
                        writer.AddAttribute("ValidateMode", "Tel");
                        imeMode = true;
                        break;
                    case ValidMode.Custom:
                        writer.AddAttribute("onkeypress", string.Format(Regular.Onkeypress, this.CustomRegexExpression));
                        writer.AddAttribute("onpaste", string.Format(Regular.Onpaste, this.CustomRegexExpression));
                        writer.AddAttribute("ondrop", string.Format(Regular.Ondrop, this.CustomRegexExpression));
                        writer.AddAttribute("ValidateMode", "Custom");
                        break;
                    default:
                        break;
                }

                //是否必须验证
                if (this.ValidateRequired)
                    writer.AddAttribute("ValidateRequired", "true");

                //设置回车时跳格
                if (this.EnterToTab)
                    writer.AddAttribute("onkeydown", "if(event.keyCode==13 && this.type != 'textarea') event.keyCode=9");

                //设置焦点样式
                if (!string.IsNullOrEmpty(this.OnfocusCssName))
                {
                    writer.AddAttribute("onfocus", string.Format("this.className='{0}'", this.OnfocusCssName));
                }
                else
                {
                    if (ValidMode != ValidMode.Date)
                    {
                        writer.AddAttribute("onfocus", "this.className='txtOnFocus'");
                    }
                }

                //设置失去焦点样式
                if (!string.IsNullOrEmpty(this.OnblurCssName))
                {
                    writer.AddAttribute("onblur", string.Format("this.className='{0}'", this.OnblurCssName));
                }
                else
                {
                    if (ValidMode != ValidMode.Date)
                    {
                        writer.AddAttribute("onblur", "this.className='txtOnBlur'");
                    }
                }

                ////是否禁止输入法切换
                //if (!string.IsNullOrEmpty(OnblurEvent))
                //    writer.AddAttribute("OnblurEvent", OnblurEvent);

                //是否禁止输入法切换
                if (imeMode)
                    writer.AddStyleAttribute("ime-mode", "disabled");

                base.AddAttributesToRender(writer);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.ToString());
            }
        }

        #endregion

        /// <summary>
        /// 正则表达式公式
        /// </summary>
        private class Regular
        {
            public static string Chinese = @"/^[\u4E00-\u9FA5]*$/";
            public static string Lower = @"/^[a-z]*$/";
            public static string Number = @"/^[0-9]*$/";
            public static string Phone = @"/^\d{1,4}([-\/](\d{1,8}?)?)?$/";
            public static string IP = @"/^\d{1,3}([.\/](\d{1,3}([.\/](\d{1,3}([.\/](\d{1,3}([.\/](\d{1,3}([.\/](\d{1,3}?)?)?)?)?)?)?)?)?)?)?$/";
            public static string Upper = @"/^[A-Z]*$/";
            //public static string Onkeypress = @"return regInput(this,{0},String.fromCharCode(keyCode))";
            public static string Onkeypress = @"return regInput(this,{0},String.fromCharCode(event.keyCode))";
            public static string Onpaste = @"return regInput(this,{0},window.clipboardData.getData('Text'))";
            public static string Ondrop = @"return regInput(this,{0},event.dataTransfer.getData('Text'))";
        }
    }
}
